home *** CD-ROM | disk | FTP | other *** search
/ Computer Shopper 242 / Issue 242 - April 2008 - DPCS0408DVD.ISO / Open Source / AutoHotKey / Source / AutoHotkey104705_source.exe / source / hotkey.h < prev    next >
Encoding:
C/C++ Source or Header  |  2007-06-02  |  17.5 KB  |  367 lines

  1. /*
  2. AutoHotkey
  3.  
  4. Copyright 2003-2007 Chris Mallett (support@autohotkey.com)
  5.  
  6. This program is free software; you can redistribute it and/or
  7. modify it under the terms of the GNU General Public License
  8. as published by the Free Software Foundation; either version 2
  9. of the License, or (at your option) any later version.
  10.  
  11. This program is distributed in the hope that it will be useful,
  12. but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  14. GNU General Public License for more details.
  15. */
  16.  
  17. #ifndef hotkey_h
  18. #define hotkey_h
  19.  
  20. #include "keyboard_mouse.h"
  21. #include "script.h"  // For which label (and in turn which line) in the script to jump to.
  22. EXTERN_SCRIPT;  // For g_script.
  23.  
  24. // Due to control/alt/shift modifiers, quite a lot of hotkey combinations are possible, so support any
  25. // conceivable use.  Note: Increasing this value will increase the memory required (i.e. any arrays
  26. // that use this value):
  27. #define MAX_HOTKEYS 700
  28.  
  29. // Note: 0xBFFF is the largest ID that can be used with RegisterHotkey().
  30. // But further limit this to 0x3FFF (16,383) so that the two highest order bits
  31. // are reserved for our other uses:
  32. #define HOTKEY_FUTURE_USE              0x8000  // Formerly HOTKEY_NO_SUPPRESS but no longer needed for that.
  33. #define HOTKEY_KEY_UP                  0x4000
  34. #define HOTKEY_ID_MASK                 0x3FFF
  35. #define HOTKEY_ID_INVALID              HOTKEY_ID_MASK
  36. #define HOTKEY_ID_ALT_TAB              0x3FFE
  37. #define HOTKEY_ID_ALT_TAB_SHIFT        0x3FFD
  38. #define HOTKEY_ID_ALT_TAB_MENU         0x3FFC
  39. #define HOTKEY_ID_ALT_TAB_AND_MENU     0x3FFB
  40. #define HOTKEY_ID_ALT_TAB_MENU_DISMISS 0x3FFA
  41. #define HOTKEY_ID_MAX                  0x3FF9  // 16377 hotkeys
  42. #define HOTKEY_ID_ON                   0x01  // This and the next 2 are used only for convenience by ConvertAltTab().
  43. #define HOTKEY_ID_OFF                  0x02
  44. #define HOTKEY_ID_TOGGLE               0x03
  45. #define IS_ALT_TAB(id) (id > HOTKEY_ID_MAX && id < HOTKEY_ID_INVALID)
  46.  
  47. #define COMPOSITE_DELIMITER " & "
  48. #define COMPOSITE_DELIMITER_LENGTH 3
  49.  
  50. // Smallest workable size: to save mem in some large arrays that use this:
  51. typedef USHORT HotkeyIDType; // This is relied upon to be unsigned; e.g. many places omit a check for ID < 0.
  52. typedef HotkeyIDType HookActionType;
  53.  
  54. typedef UCHAR HotkeyTypeType;
  55. enum HotkeyTypeEnum {HK_NORMAL, HK_KEYBD_HOOK, HK_MOUSE_HOOK, HK_BOTH_HOOKS, HK_JOYSTICK};
  56. // If above numbers are ever changed/reshuffled, update the macros below.
  57. #define HK_TYPE_CAN_BECOME_KEYBD_HOOK(type) (type == HK_NORMAL)
  58. #define HK_TYPE_IS_HOOK(type) (type > HK_NORMAL && type < HK_JOYSTICK)
  59.  
  60. typedef UCHAR HotCriterionType;
  61. enum HotCriterionEnum {HOT_NO_CRITERION, HOT_IF_ACTIVE, HOT_IF_NOT_ACTIVE, HOT_IF_EXIST, HOT_IF_NOT_EXIST}; // HOT_NO_CRITERION must be zero.
  62. HWND HotCriterionAllowsFiring(HotCriterionType aHotCriterion, char *aWinTitle, char *aWinText); // Used by hotkeys and hotstrings.
  63. ResultType SetGlobalHotTitleText(char *aWinTitle, char *aWinText);
  64.  
  65.  
  66.  
  67. struct HotkeyCriterion
  68. {
  69.     char *mHotWinTitle, *mHotWinText;
  70.     HotkeyCriterion *mNextCriterion;
  71. };
  72.  
  73.  
  74.  
  75. struct HotkeyVariant
  76. {
  77.     Label *mJumpToLabel;
  78.     DWORD mRunAgainTime;
  79.     char *mHotWinTitle, *mHotWinText;
  80.     HotkeyVariant *mNextVariant;
  81.     int mPriority;
  82.     // Keep members that are less than 32-bit adjacent to each other to conserve memory in with the default
  83.     // 4-byte alignment:
  84.     HotCriterionType mHotCriterion;
  85.     UCHAR mExistingThreads, mMaxThreads;
  86.     bool mNoSuppress; // v1.0.44: This became a per-variant attribute because it's more useful/flexible that way.
  87.     bool mMaxThreadsBuffer;
  88.     bool mRunAgainAfterFinished;
  89.     bool mEnabled; // Whether this variant has been disabled via the Hotkey command.
  90. };
  91.  
  92.  
  93.  
  94. class Hotkey
  95. {
  96. private:
  97.     // These are done as static, rather than having an outer-class to contain all the hotkeys, because
  98.     // the hotkey ID is used as the array index for performance reasons.  Having an outer class implies
  99.     // the potential future use of more than one set of hotkeys, which could still be implemented
  100.     // within static data and methods to retain the indexing/performance method:
  101.     static HookType sWhichHookNeeded;
  102.     static HookType sWhichHookAlways;
  103.     static DWORD sTimePrev;
  104.     static DWORD sTimeNow;
  105.     static HotkeyIDType sNextID;
  106.  
  107.     bool Enable(HotkeyVariant &aVariant) // Returns true if the variant needed to be disabled, in which case caller should generally call ManifestAllHotkeysHotstringsHooks().
  108.     {
  109.         if (aVariant.mEnabled) // Added for v1.0.23 to greatly improve performance when hotkey is already in the right state.
  110.             return false; // Indicate that it's already enabled.
  111.         aVariant.mEnabled = true;
  112.         return true;
  113.     }
  114.  
  115.     bool Disable(HotkeyVariant &aVariant) // Returns true if the variant needed to be disabled, in which case caller should generally call ManifestAllHotkeysHotstringsHooks().
  116.     {
  117.         if (!aVariant.mEnabled) // Added for v1.0.23 to greatly improve performance when hotkey is already in the right state.
  118.             return false; // Indicate that it's already disabled.
  119.         aVariant.mEnabled = false;
  120.         aVariant.mRunAgainAfterFinished = false; // ManifestAllHotkeysHotstringsHooks() won't do this unless the entire hotkey is disabled/unregistered.
  121.         return true;
  122.     }
  123.  
  124.     bool EnableParent() // Returns true if the hotkey needed to be disabled, in which case caller should generally call ManifestAllHotkeysHotstringsHooks().
  125.     {
  126.         if (mParentEnabled)
  127.             return false; // Indicate that it's already enabled.
  128.         mParentEnabled = true;
  129.         return true;
  130.     }
  131.  
  132.     bool DisableParent() // Returns true if the hotkey needed to be disabled, in which case caller should generally call ManifestAllHotkeysHotstringsHooks().
  133.     {
  134.         if (!mParentEnabled)
  135.             return false; // Indicate that it's already disabled.
  136.         mParentEnabled = false;
  137.         return true;
  138.     }
  139.  
  140.     ResultType Register();
  141.     ResultType Unregister();
  142.  
  143.     void *operator new(size_t aBytes) {return SimpleHeap::Malloc(aBytes);}
  144.     void *operator new[](size_t aBytes) {return SimpleHeap::Malloc(aBytes);}
  145.     void operator delete(void *aPtr) {SimpleHeap::Delete(aPtr);}  // Deletes aPtr if it was the most recently allocated.
  146.     void operator delete[](void *aPtr) {SimpleHeap::Delete(aPtr);}
  147.  
  148.     // For now, constructor & destructor are private so that only static methods can create new
  149.     // objects.  This allow proper tracking of which OS hotkey IDs have been used.
  150.     Hotkey(HotkeyIDType aID, Label *aJumpToLabel, HookActionType aHookAction, char *aName, bool aSuffixHasTilde, bool aUseErrorLevel);
  151.     ~Hotkey() {if (mIsRegistered) Unregister();}
  152.  
  153. public:
  154.     static Hotkey *shk[MAX_HOTKEYS];
  155.     HotkeyIDType mID;  // Must be unique for each hotkey of a given thread.
  156.     HookActionType mHookAction;
  157.  
  158.     char *mName; // Points to the label name for static hotkeys, or a dynamically-allocated string for dynamic hotkeys.
  159.     sc_type mSC; // Scan code.  All vk's have a scan code, but not vice versa.
  160.     sc_type mModifierSC; // If mModifierVK is zero, this scan code, if non-zero, will be used as the modifier.
  161.     mod_type mModifiers;  // MOD_ALT, MOD_CONTROL, MOD_SHIFT, MOD_WIN, or some additive or bitwise-or combination of these.
  162.     modLR_type mModifiersLR;  // Left-right centric versions of the above.
  163.     modLR_type mModifiersConsolidatedLR; // The combination of mModifierVK, mModifierSC, mModifiersLR, modifiers
  164.  
  165.     // Keep single-byte attributes adjacent to each other to conserve memory within byte-aligned class/struct:
  166.     vk_type mVK; // virtual-key code, e.g. VK_TAB, VK_LWIN, VK_LMENU, VK_APPS, VK_F10.  If zero, use sc below.
  167.     vk_type mModifierVK; // Any other virtual key that must be pressed down in order to activate "vk" itself.
  168.     HotkeyTypeType mType;
  169.     #define NO_SUPPRESS_PREFIX 0x01               // Bitwise: Bit #1
  170.     #define AT_LEAST_ONE_VARIANT_HAS_TILDE 0x02   // Bitwise: Bit #2
  171.     #define AT_LEAST_ONE_VARIANT_LACKS_TILDE 0x04 // Bitwise: Bit #3
  172.     #define NO_SUPPRESS_NEXT_UP_EVENT 0x08        // Bitwise: Bit #4
  173.     #define NO_SUPPRESS_SUFFIX_VARIES (AT_LEAST_ONE_VARIANT_HAS_TILDE | AT_LEAST_ONE_VARIANT_LACKS_TILDE) // i.e. a hotkey that has variants of both types.
  174.     #define NO_SUPPRESS_STATES NO_SUPPRESS_NEXT_UP_EVENT  // This is a bitwise union (currently only one item) of those of the above that represent a the key's dynamically changing state as the user types.
  175.  
  176.     UCHAR mNoSuppress;  // Uses the flags above.  Normally 0, but can be overridden by using the hotkey tilde (~) prefix).
  177.     bool mKeybdHookMandatory;
  178.     bool mAllowExtraModifiers;  // False if the hotkey should not fire when extraneous modifiers are held down.
  179.     bool mKeyUp; // A hotkey that should fire on key-up.
  180.     bool mVK_WasSpecifiedByNumber; // A hotkey defined by something like "VK24::" or "Hotkey, VK24, ..."
  181.     bool mUnregisterDuringThread; // Win9x: Whether this hotkey should be unregistered during its own subroutine (to prevent its own Send commmand from firing itself).  Seems okay to apply this to all variants.
  182.     bool mIsRegistered;  // Whether this hotkey has been successfully registered.
  183.     bool mParentEnabled; // When true, the individual variants' mEnabled flags matter. When false, the entire hotkey is disabled.
  184.     bool mConstructedOK;
  185.  
  186.     HotkeyVariant *mFirstVariant, *mLastVariant; // v1.0.42: Linked list of variant hotkeys created via #IfWin directives.
  187.  
  188.     // Make sHotkeyCount an alias for sNextID.  Make it const to enforce modifying the value in only one way:
  189.     static const HotkeyIDType &sHotkeyCount;
  190.     static bool sJoystickHasHotkeys[MAX_JOYSTICKS];
  191.     static DWORD sJoyHotkeyCount;
  192.  
  193.     static void AllDestructAndExit(int exit_code);
  194.  
  195.     #define HOTKEY_EL_BADLABEL           "1" // Set as strings so that SetFormat doesn't affect their appearance (for use with "If ErrorLevel in 5,6").
  196.     #define HOTKEY_EL_INVALID_KEYNAME    "2"
  197.     #define HOTKEY_EL_UNSUPPORTED_PREFIX "3"
  198.     #define HOTKEY_EL_ALTTAB             "4"
  199.     #define HOTKEY_EL_NOTEXIST           "5"
  200.     #define HOTKEY_EL_NOTEXISTVARIANT    "6"
  201.     #define HOTKEY_EL_WIN9X              "50"
  202.     #define HOTKEY_EL_NOREG              "51"
  203.     #define HOTKEY_EL_MAXCOUNT           "98" // 98 allows room for other ErrorLevels to be added in between.
  204.     #define HOTKEY_EL_MEM                "99"
  205.     static ResultType Dynamic(char *aHotkeyName, char *aLabelName, char *aOptions, Label *aJumpToLabel);
  206.  
  207.     static Hotkey *AddHotkey(Label *aJumpToLabel, HookActionType aHookAction, char *aName, bool aSuffixHasTilde, bool aUseErrorLevel);
  208.     HotkeyVariant *FindVariant();
  209.     HotkeyVariant *AddVariant(Label *aJumpToLabel, bool aSuffixHasTilde);
  210.     static bool PrefixHasNoEnabledSuffixes(int aVKorSC, bool aIsSC);
  211.     HotkeyVariant *CriterionAllowsFiring(HWND *aFoundHWND = NULL);
  212.     static HotkeyVariant *CriterionAllowsFiring(HotkeyIDType aHotkeyID, HWND &aFoundHWND);
  213.     static bool CriterionFiringIsCertain(HotkeyIDType &aHotkeyIDwithFlags, bool aKeyUp, UCHAR &aNoSuppress
  214.         , bool &aFireWithNoSuppress, char *aSingleChar);
  215.     static void TriggerJoyHotkeys(int aJoystickID, DWORD aButtonsNewlyDown);
  216.     void Perform(HotkeyVariant &aVariant);
  217.     static void ManifestAllHotkeysHotstringsHooks();
  218.     static void RequireHook(HookType aWhichHook) {sWhichHookAlways |= aWhichHook;}
  219.     static ResultType TextInterpret(char *aName, Hotkey *aThisHotkey, bool aUseErrorLevel);
  220.  
  221.     struct HotkeyProperties // Struct used by TextToModifiers() and its callers.
  222.     {
  223.         mod_type modifiers;
  224.         modLR_type modifiersLR;
  225.         char prefix_text[32];  // Has to be large enough to hold the largest key name in g_key_to_vk,
  226.         char suffix_text[32];  // which is probably "Browser_Favorites" (17).
  227.         bool suffix_has_tilde; // As opposed to "prefix has tilde".
  228.         bool has_asterisk;
  229.         bool is_key_up;
  230.     };
  231.     static char *TextToModifiers(char *aText, Hotkey *aThisHotkey, HotkeyProperties *aProperties = NULL);
  232.     static ResultType TextToKey(char *aText, char *aHotkeyName, bool aIsModifier, Hotkey *aThisHotkey, bool aUseErrorLevel);
  233.  
  234.     static void InstallKeybdHook();
  235.     static void InstallMouseHook();
  236.  
  237.     bool PerformIsAllowed(HotkeyVariant &aVariant)
  238.     {
  239.         // For now, attempts to launch another simultaneous instance of this subroutine
  240.         // are ignored if MaxThreadsPerHotkey (for this particular hotkey) has been reached.
  241.         // In the future, it might be better to have this user-configurable, i.e. to devise
  242.         // some way for the hotkeys to be kept queued up so that they take effect only when
  243.         // the number of currently active threads drops below the max.  But doing such
  244.         // might make "infinite key loops" harder to catch because the rate of incoming hotkeys
  245.         // would be slowed down to prevent the subroutines from running concurrently:
  246.         return aVariant.mExistingThreads < aVariant.mMaxThreads
  247.             || (ACT_IS_ALWAYS_ALLOWED(aVariant.mJumpToLabel->mJumpToLine->mActionType));
  248.     }
  249.  
  250.     bool IsExemptFromSuspend() // A hotkey is considered exempt if even one of its variants is exempt.
  251.     {
  252.         // It's the caller's responsibility to check vp->mEnabled; that isn't done here.
  253.         if (mHookAction) // An alt-tab hotkey (which overrides all its variants) is never exempt.
  254.             return false;
  255.         for (HotkeyVariant *vp = mFirstVariant; vp; vp = vp->mNextVariant)
  256.             if (vp->mJumpToLabel->IsExemptFromSuspend()) // If it has no label, it's never exempt.
  257.                 return true; // Even a single exempt variant makes the entire hotkey exempt.
  258.         // Otherwise, since the above didn't find any exempt variants, the entire hotkey is non-exempt:
  259.         return false;
  260.     }
  261.  
  262.     bool IsCompletelyDisabled()
  263.     {
  264.         if (mHookAction) // Alt tab hotkeys are disabled completely if and only if the parent is disabled.
  265.             return !mParentEnabled;
  266.         for (HotkeyVariant *vp = mFirstVariant; vp; vp = vp->mNextVariant)
  267.             if (vp->mEnabled)
  268.                 return false;
  269.         return true;
  270.     }
  271.  
  272.     static void RunAgainAfterFinished(HotkeyVariant &aVariant)
  273.     {
  274.         if (aVariant.mMaxThreadsBuffer)
  275.             aVariant.mRunAgainAfterFinished = true;
  276.         aVariant.mRunAgainTime = GetTickCount();
  277.         // Above: The time this event was buffered, to make sure it doesn't get too old.
  278.     }
  279.  
  280.     static void ResetRunAgainAfterFinished()  // For all hotkeys and all variants of each.
  281.     {
  282.         HotkeyVariant *vp;
  283.         for (int i = 0; i < sHotkeyCount; ++i)
  284.             for (vp = shk[i]->mFirstVariant; vp; vp = vp->mNextVariant)
  285.                 vp->mRunAgainAfterFinished = false;
  286.     }
  287.  
  288.     static HookActionType ConvertAltTab(char *aBuf, bool aAllowOnOff)
  289.     {
  290.         if (!aBuf || !*aBuf) return 0;
  291.         if (!stricmp(aBuf, "AltTab")) return HOTKEY_ID_ALT_TAB;
  292.         if (!stricmp(aBuf, "ShiftAltTab")) return HOTKEY_ID_ALT_TAB_SHIFT;
  293.         if (!stricmp(aBuf, "AltTabMenu")) return HOTKEY_ID_ALT_TAB_MENU;
  294.         if (!stricmp(aBuf, "AltTabAndMenu")) return HOTKEY_ID_ALT_TAB_AND_MENU;
  295.         if (!stricmp(aBuf, "AltTabMenuDismiss")) return HOTKEY_ID_ALT_TAB_MENU_DISMISS;
  296.         if (aAllowOnOff)
  297.         {
  298.             if (!stricmp(aBuf, "On")) return HOTKEY_ID_ON;
  299.             if (!stricmp(aBuf, "Off")) return HOTKEY_ID_OFF;
  300.             if (!stricmp(aBuf, "Toggle")) return HOTKEY_ID_TOGGLE;
  301.         }
  302.         return 0;
  303.     }
  304.  
  305.     static Hotkey *FindHotkeyByTrueNature(char *aName, bool &aSuffixHasTilde);
  306.     static Hotkey *FindHotkeyContainingModLR(modLR_type aModifiersLR);  //, HotkeyIDType hotkey_id_to_omit);
  307.     //static Hotkey *FindHotkeyWithThisModifier(vk_type aVK, sc_type aSC);
  308.     //static Hotkey *FindHotkeyBySC(sc2_type aSC2, mod_type aModifiers, modLR_type aModifiersLR);
  309.  
  310.     static char *ListHotkeys(char *aBuf, int aBufSize);
  311.     char *ToText(char *aBuf, int aBufSize, bool aAppendNewline);
  312. };
  313.  
  314.  
  315. ///////////////////////////////////////////////////////////////////////////////////
  316.  
  317. #define MAX_HOTSTRING_LENGTH 40  // Hard to imagine a need for more than this, and most are only a few chars long.
  318. #define MAX_HOTSTRING_LENGTH_STR "40"  // Keep in sync with the above.
  319. #define HOTSTRING_BLOCK_SIZE 1024
  320. typedef UINT HotstringIDType;
  321.  
  322. enum CaseConformModes {CASE_CONFORM_NONE, CASE_CONFORM_ALL_CAPS, CASE_CONFORM_FIRST_CAP};
  323.  
  324.  
  325. class Hotstring
  326. {
  327. public:
  328.     static Hotstring **shs;  // An array to be allocated on first use (performs better than linked list).
  329.     static HotstringIDType sHotstringCount;
  330.     static HotstringIDType sHotstringCountMax;
  331.     static bool mAtLeastOneEnabled; // v1.0.44.08: For performance, such as avoiding calling ToAsciiEx() in the hook.
  332.  
  333.     Label *mJumpToLabel;
  334.     char *mString, *mReplacement, *mHotWinTitle, *mHotWinText;
  335.     int mPriority, mKeyDelay;
  336.  
  337.     // Keep members that are smaller than 32-bit adjacent with each other to conserve memory (due to 4-byte alignment).
  338.     SendModes mSendMode;
  339.     HotCriterionType mHotCriterion;
  340.     UCHAR mStringLength;
  341.     bool mSuspended;
  342.     UCHAR mExistingThreads, mMaxThreads;
  343.     bool mCaseSensitive, mConformToCase, mDoBackspace, mOmitEndChar, mSendRaw, mEndCharRequired
  344.         , mDetectWhenInsideWord, mDoReset, mConstructedOK;
  345.  
  346.     static void SuspendAll(bool aSuspend);
  347.     ResultType Perform();
  348.     void DoReplace(LPARAM alParam);
  349.     static ResultType AddHotstring(Label *aJumpToLabel, char *aOptions, char *aHotstring, char *aReplacement
  350.         , bool aHasContinuationSection);
  351.     static void ParseOptions(char *aOptions, int &aPriority, int &aKeyDelay, SendModes &aSendMode
  352.         , bool &aCaseSensitive, bool &aConformToCase, bool &aDoBackspace, bool &aOmitEndChar, bool &aSendRaw
  353.         , bool &aEndCharRequired, bool &aDetectWhenInsideWord, bool &aDoReset);
  354.  
  355.     // Constructor & destructor:
  356.     Hotstring(Label *aJumpToLabel, char *aOptions, char *aHotstring, char *aReplacement, bool aHasContinuationSection);
  357.     ~Hotstring() {}  // Note that mReplacement is sometimes malloc'd, sometimes from SimpleHeap, and sometimes the empty string.
  358.  
  359.     void *operator new(size_t aBytes) {return SimpleHeap::Malloc(aBytes);}
  360.     void *operator new[](size_t aBytes) {return SimpleHeap::Malloc(aBytes);}
  361.     void operator delete(void *aPtr) {SimpleHeap::Delete(aPtr);}  // Deletes aPtr if it was the most recently allocated.
  362.     void operator delete[](void *aPtr) {SimpleHeap::Delete(aPtr);}
  363. };
  364.  
  365.  
  366. #endif
  367.